/*

Summary:
Use to split a string with specified splitter, which
could be a char, several chars or a string.

Remark:
The Split function uses output iterator to output results.

Split uses functions or function objects called scanner to
determinate whether there is a splitter. Scanners accept
a char parameter, and return splitter's length. Split 
enumerates all chars in the string, and call scanner one by
one, to get the length of splitter.

Because Split calls scanner with only one char, scanners should
save the scan state itself. And once the char sequence fits
whole splitter, scanners clear the state and return the length.
Otherwise they change the state and return 0.
	
There are three predefine scanners, for single char splitter,
several chars splitter and string splitter respectively. If 
user want a specifal scanner, he can implement a new scanner
himself.

Version:
0.0.1

LastUpdatedDate:
2012-09-19
	
CreatedDate:
2012-09-19

*/

#pragma once

#include <string>


namespace Zaf {
namespace String {


template<typename CharType>
struct StringSplitterScanner {

public:
	StringSplitterScanner(const std::basic_string<CharType>& str) : m_str(str), m_matchLen(0) {	}

	unsigned int operator()(CharType ch) {

		if (m_str.empty() == true) {
			return 0;
		}

		if (m_str[m_matchLen] == ch) {
			++m_matchLen;
		}
		else {
			m_matchLen = 0;
		}

		if (m_matchLen == m_str.length()) {
			m_matchLen = 0;
			return m_str.length();
		}

		return 0;
	}

private:
	unsigned int m_matchLen;
	std::basic_string<CharType> m_str;
};



template<typename CharType>
struct CharSplitterScanner {

public:
	CharSplitterScanner(CharType ch) { 
		m_ch = ch;
	}

	unsigned int operator()(CharType ch) {
		return m_ch == ch ? 1 : 0;
	}

private:
	CharType m_ch;
};



template<typename CharType>
struct CharArraySplitterScanner {

public:
	CharArraySplitterScanner(const std::basic_string<CharType>& arr) : m_array(arr) {

	}

	unsigned int operator()(CharType ch) {
		return m_array.find(ch) != -1 ? 1 : 0; 
	}

private:
	std::basic_string<CharType> m_array;
};



template<typename CharType, typename OutputIteratorType, typename SplitterScanner>
void Split(const CharType* begin, OutputIteratorType outputIt, SplitterScanner scanner) {

	const CharType* pre = begin;
	const CharType* cur = begin;

	while (*cur != 0) {

		unsigned int splitterLen = scanner(*cur);

		if (splitterLen != 0) {

			*outputIt = std::basic_string<CharType>(pre, cur - splitterLen + 1);

			pre = cur + 1;
		}

		++cur;
	}

	*outputIt = std::basic_string<CharType>(pre);
}



template<typename CharType, typename OutputIteratorType, typename SplitterScanner>
void Split(const std::basic_string<CharType>& str, OutputIteratorType outputIt, SplitterScanner scanner) {
	Split(str.c_str(), outputIt, scanner);
}



}
}